package com.dq.service.subscribe.impl;

import com.dq.controller.in.SubscribePayRequest;
import com.dq.controller.in.TimeQuery;
import com.dq.controller.in.user.WxUserQuery;
import com.dq.controller.in.*;
import com.dq.domain.evaluation.EvaluationRecord;
import com.dq.domain.org.OrgTimeQuantum;
import com.dq.domain.service.ServiceProject;
import com.dq.domain.sys.section.SysSection;
import com.dq.domain.sys.user.user.BossUser;
import com.dq.domain.sys.user.Account;
import com.dq.domain.sys.user.user.BossUser;
import com.dq.domain.sys.user.user.WxUser;
import com.dq.domain.sys.user.user.centre.*;
import com.dq.dto.SubscribeTimeDto;
import com.dq.exception.customException.AdminException;
import com.dq.controller.in.request.SubscribeAdd;
import com.dq.controller.in.base.BaseAdminQuery;
import com.dq.service.account.AccountService;
import com.dq.service.org.OrgService;
import com.dq.service.sys.user.WxUserService;
import com.dq.service.sys.user.centre.UserAccountStaffUserService;
import com.dq.utils.TimeUtil;
import com.dq.vo.ListDataVo;
import com.dq.vo.Vo;
import com.dq.domain.subscribe.Subscribe;
import com.dq.domain.base.AbstractEntity;
import com.dq.domain.base.impl.BaseDaoImpl;

import com.dq.domain.message.oneself.SubscribeMessage;
import com.dq.domain.org.Org;
import com.dq.domain.record.RestDayRecord;
import com.dq.domain.record.ServiceRecord;
import com.dq.domain.sys.user.user.StaffUser;
import com.dq.domain.sys.user.user.base.SysUser;
import com.dq.repository.BaseRepositories;
import com.dq.service.messsge.SubscribeMessageService;
import com.dq.service.subscribe.SubscribeService;
import com.dq.vo.baseVo.VO;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.tools.Tool;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.LocalTime;
import java.util.*;

/**
 * @Author luchangtong
 * @Date 2019/12/2 15:45
 */
@Service
public class SubscribeServiceImpl extends BaseRepositories implements SubscribeService {
    @Autowired
    private SubscribeMessageService subscribeMessageService;
    @Autowired
    protected WxUserService wxUserService;
    @Autowired
    private UserAccountStaffUserService userAccountStaffUserService;
    @Autowired
    private AccountService accountService;
    @Autowired
    protected OrgService orgService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void subscribe(SubscribeAdd subscribeAdd) throws AdminException {
        SysUser loginUser = sysUserService.getUserInSection();
        Org org = dao.get(Org.class, subscribeAdd.getOrgId());
        if (org == null) {
            throw new AdminException("选择门店异常");
        }
        if (loginUser.getSection() == null) {
            loginUser.setSection(org);
            sysUserRepository.save(loginUser);
        }
        ServiceProject serviceProject = dao.get(ServiceProject.class, subscribeAdd.getServiceProjectId());
        if (null == serviceProject) {
            throw new AdminException("服务项目异常");
        }
        //1:线上预约 2：线下预约
        if (subscribeAdd.getType() != null && subscribeAdd.getType() == 2) {
            loginUser = dao.get(SysUser.class, subscribeAdd.getWxUserId());
        }
//        if(user == null || user.getSection() ==null || user.getSection().getId() == null){
        if (loginUser == null) {
            throw new AdminException("登录用户异常");
        }
        if (subscribeAdd.getBeginTime() == null) {
            throw new AdminException("预约时间异常");
        }
        if (subscribeAdd.getBeginTime() < System.currentTimeMillis()) {
            throw new AdminException("请检查预约时间");
        }
        BossUser staffUser = dao.get(BossUser.class, subscribeAdd.getStaffUserId());
        if (staffUser == null) {
            throw new AdminException("无对应技师");
        }
        Long endTime = TimeUtil.formatFMT6Date(TimeUtil.minutesAddFMT_6(new DateTime(subscribeAdd.getBeginTime()), serviceProject.getServiceTime().intValue()).toString());
        List<Subscribe.SubscribeStatus> statuses = new ArrayList<>();
        statuses.add(Subscribe.SubscribeStatus.processing);
        statuses.add(Subscribe.SubscribeStatus.confirmed);
        statuses.add(Subscribe.SubscribeStatus.cancelled);
        statuses.add(Subscribe.SubscribeStatus.inservice);
//        List<Subscribe> subscribes = subscribeRepository.findByWxUserAndSysDeptAndTechnicianUserAndDeletedFalseAndBeginTimeAndEndTimeAndSubscribeStatusIn(loginUser, (Org) loginUser.getSection(),staffUser,subscribeAdd.getBeginTime(),endTime,statuses);
        List<Subscribe> subscribes = subscribeRepository.findByWxUserAndTechnicianUserAndDeletedFalseAndBeginTimeAndEndTimeAndSubscribeStatusIn(loginUser, staffUser, subscribeAdd.getBeginTime(), endTime, statuses);
        if (subscribes.size() > 0) {
            throw new AdminException("不能重复预约");
        }

        Subscribe subscribe = new Subscribe();
        if (!(loginUser instanceof WxUser)) {
            throw new AdminException("用户转wxuser异常");
        }
        SysSection section = loginUser.getSection();
        if (section != null) {
            subscribe.setOriginalOrg(section);
        }
        subscribe.setWxUser((WxUser) loginUser);
        subscribe.setSubscribeNo(AbstractEntity.generyStrAndMstime(""));
        subscribe.setSysDept(org);
        subscribe.setTechnicianUser(staffUser);
        subscribe.setBeginTime(subscribeAdd.getBeginTime());
        subscribe.setEndTime(endTime);
        subscribe.setSubscribeStatus(Subscribe.SubscribeStatus.confirmed);
        subscribe.setServiceProject(serviceProject);
        subscribe.setTimeoutTime(TimeUtil.formatFMT6Date(TimeUtil.minutesAddFMT_6(new DateTime(endTime), 30).toString()));
        if (subscribeAdd.getSubscribeType() == null) {
            subscribe.setSubscribeType(Subscribe.SubscribeType.normal);
        } else {
            subscribe.setSubscribeType(subscribeAdd.getSubscribeType());
        }
        if (subscribeAdd.getType() == 2) {
            subscribe.setSubscribeStatus(Subscribe.SubscribeStatus.processing);
        }

        String errorMsg = "";
        Subscribe save = subscribeRepository.save(subscribe);

        if (StringUtils.isNotBlank(errorMsg)) {
            throw new AdminException(errorMsg);
        } else {
//            try {
//                // 发送预约消息
//                subscribeMessage(save, loginUser, SubscribeMessage.UserType.staff, "预约成功");
//                // 开启延时任务 消息提醒
//                subscribeMessageService.subscribeRedisBegin(save);
//            }catch (Exception e) {
//                e.printStackTrace();
//            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void subscribeMessage(Subscribe subscribe, SysUser user, SubscribeMessage.UserType userType, String content) throws AdminException {
        SubscribeMessage subscribeMessage = new SubscribeMessage();
        subscribeMessage.setSubscribe(subscribe);
        subscribeMessage.setCaseUser(user);
        String theme = "";
        if (StringUtils.isEmpty(user.getUserRealcName())) {
            theme = user.getUsername();
        } else {
            theme = user.getUserRealcName();
        }
        subscribeMessage.setTheme(theme);

        subscribeMessageService.save(subscribeMessage, userType, content);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelSubscribe(Subscribe subscribe, String content) throws AdminException {
        subscribe.setSubscribeStatus(Subscribe.SubscribeStatus.cancel);
        Subscribe save = subscribeRepository.save(subscribe);
        try {
            subscribeMessage(save, save.getWxUser(), SubscribeMessage.UserType.client, content);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public Map<String, Object> createQuery(StaffSubscribeQuery staffSubscribeQuery) throws AdminException {
        Map<String, Object> query = staffSubscribeQuery.parseMap();
        if (staffSubscribeQuery.getOrgId() != null) {
            query.put("sysDept_id", staffSubscribeQuery.getOrgId());
            query.remove("orgId");
        }
        if (staffSubscribeQuery.getStaffUserId() != null) {
            query.put("technicianUser_id", staffSubscribeQuery.getStaffUserId());
            query.remove("staffUserId");
        }
        if (staffSubscribeQuery.getWxUserId() != null) {
            query.put("wxUser_id", staffSubscribeQuery.getWxUserId());
            query.remove("wxUserId");
        }
        if (StringUtils.isNotEmpty(staffSubscribeQuery.getSubscribeNo())) {
            query.put("subscribeNo" + BaseDaoImpl.likeSqlStr, BaseAdminQuery.likeSql(staffSubscribeQuery.getCardNo()));
            query.remove("subscribeNo");
        }
        if (StringUtils.isNotEmpty(staffSubscribeQuery.getCardNo())) {
            query.put("wxUser_cardNo" + BaseDaoImpl.likeSqlStr, BaseAdminQuery.likeSql(staffSubscribeQuery.getCardNo()));
            query.remove("cardNo");
        }
        if (StringUtils.isNotEmpty(staffSubscribeQuery.getMobile())) {
            query.put("wxUser_mobile" + BaseDaoImpl.likeSqlStr, BaseAdminQuery.likeSql(staffSubscribeQuery.getMobile()));
            query.remove("mobile");
        }
        if (StringUtils.isNotEmpty(staffSubscribeQuery.getUserRealcName())) {
            query.put("wxUser_userRealcName" + BaseDaoImpl.likeSqlStr, BaseAdminQuery.likeSql(staffSubscribeQuery.getUserRealcName()));
            query.remove("userRealcName");
        }
        if (staffSubscribeQuery.getBeginTime() != null) {
            query.put("beginTime" + BaseDaoImpl.gteSqlStr, staffSubscribeQuery.getBeginTime());
            query.remove("beginTime");
        }
        if (staffSubscribeQuery.getEndTime() != null) {
            query.put("endTime" + BaseDaoImpl.lteSqlStr, staffSubscribeQuery.getEndTime());
            query.remove("endTime");
        }
        if (!"".equals(staffSubscribeQuery.getValue()) && staffSubscribeQuery.getValue() != null) {
            Map<String, Object> keyQuery = new HashMap<>(16);

            keyQuery.put("wxUser_userRealcName" + BaseDaoImpl.likeSqlStr, BaseAdminQuery.likeSql(staffSubscribeQuery.getValue()));
            keyQuery.put("wxUser_cardNo" + BaseDaoImpl.likeSqlStr, BaseAdminQuery.likeSql(staffSubscribeQuery.getValue()));

            query.put("keyQuery" + BaseDaoImpl.orAndSqlStr, keyQuery);
            query.remove("value");
        }
        return query;
    }

    @Override
    public List<Subscribe> subscribeList(StaffSubscribeQuery staffSubscribeQuery) throws AdminException {
        staffSubscribeQuery.format();
        Map<String, Object> query = createQuery(staffSubscribeQuery);

        return dao.find(dao.query2Hql(Subscribe.class, query), query);
    }

    @Override
    public Long subscribeCount(StaffSubscribeQuery staffSubscribeQuery) throws AdminException {
        Map<String, Object> query = createQuery(staffSubscribeQuery);

        return dao.count(dao.count2Hql(Subscribe.class, query), query);
    }

    @Override
    public Vo list(StaffSubscribeQuery staffSubscribeQuery) throws AdminException {
        //测试
        // staffSubscribeQuery.setOrgId(0L);
        List<Subscribe> lists = new ArrayList<>();
        Long orgId = staffSubscribeQuery.getOrgId();
        if (null != orgId && orgId == 0) {
            //获取用户下所有门店
            List<Org> listAllByUser = orgService.getListAllByUser();
            for (Org org : listAllByUser) {
                staffSubscribeQuery.setOrgId(org.getId());
                List<Subscribe> list = subscribeList(staffSubscribeQuery);
                lists.addAll(list);
            }
        } else {
            List<Subscribe> list = subscribeList(staffSubscribeQuery);
            lists.addAll(list);
        }
        List<Subscribe.Vo> voList = (List<Subscribe.Vo>) VO.toVOCollection(lists);
        voList.forEach(vo -> {
            vo.setLableStrList(wxUserService.getWxUserLable(dao.get(WxUser.class, vo.getWxUserId())));
            if (userCardRepository.findByDeletedFalseAndWxUser(dao.get(WxUser.class, vo.getWxUserId())).size() > 0) {
                vo.setFlag(1L);
            } else {
                vo.setFlag(0L);
            }
            EvaluationRecord evaluationRecord = evaluationRecordRepository.findByDeletedFalseAndSubscribeId(vo.getId());
            if (evaluationRecord != null) {
                vo.setEvaluationRecordId(evaluationRecord.getId());
            }
        });
        return new ListDataVo(voList, subscribeCount(staffSubscribeQuery));
    }

    @Override
    public Vo findTimeByOrgAndProject(TimeQuery timeQuery) throws AdminException {
        SysUser sysUser = sysUserService.getUser();
        Org org = dao.get(Org.class, timeQuery.getOrgId());
        if (org == null) {
            throw new AdminException("门店异常");
        }
        BossUser staffUser = dao.get(BossUser.class, timeQuery.getStaffUserId());
        if (staffUser == null) {
            throw new AdminException("所选技师不存在");
        }
        String[] a = timeQuery.getTime().split("-");
        UserScheduling userScheduling = userSchedulingRepository.findByDeletedFalseAndBossUserIdAndYearAndMonthAndDay(timeQuery.getStaffUserId(), new Long(a[0]), new Long(a[1]), new Long(a[2]));
        if (userScheduling == null) {
            throw new AdminException("技师今日排班时间未设置");
        }
        if (userScheduling != null && userScheduling.getWorkStatus() != null && UserScheduling.WorkStatus.off.toString().equals(userScheduling.getWorkStatus().toString())) {
            throw new AdminException("技师今日休息");
        }
        if (StringUtils.isBlank(userScheduling.getStartTime()) || StringUtils.isBlank(userScheduling.getEndTime())) {
            throw new AdminException("技师排班时间未设置");
        }
        Long size = TimeUtil.CalTime(userScheduling.getEndTime(), userScheduling.getStartTime()) / 30;
        ArrayList<SubscribeTimeDto> subscribeTimeDtos = new ArrayList<>();
        SubscribeTimeDto dto = new SubscribeTimeDto();
        String data = userScheduling.getStartTime();
        dto.setTime(data);
        subscribeTimeDtos.add(dto);
        for (int i = 0; i < size; i++) {
            SubscribeTimeDto dto1 = new SubscribeTimeDto();
            data = TimeUtil.addTime(data);
            dto1.setTime(data);
            subscribeTimeDtos.add(dto1);
        }
        List<Subscribe.SubscribeStatus> statuses = new ArrayList<>();
        statuses.add(Subscribe.SubscribeStatus.processing);
        statuses.add(Subscribe.SubscribeStatus.confirmed);
        statuses.add(Subscribe.SubscribeStatus.inservice);
        statuses.add(Subscribe.SubscribeStatus.cancelled);
        subscribeTimeDtos.forEach(orgTimeQuantum -> {
            long time = TimeUtil.getTime(timeQuery.getTime() + " " + orgTimeQuantum.getTime() + ":00");
            System.out.println("循环时间" + time);
            if (subscribeRepository.findBySysDeptAndTechnicianUserAndDeletedFalseAndBeginTimeLessThanEqualAndEndTimeGreaterThanEqualAndSubscribeStatusIn(org, staffUser, time, time, statuses).size() > 0) {
                orgTimeQuantum.setFlag(false);
            } else {
                if (System.currentTimeMillis() > time) {
                    orgTimeQuantum.setFlag(false);
                } else {
                    orgTimeQuantum.setFlag(true);
                }
            }
        });
        return new Vo(subscribeTimeDtos);
    }

    /**
     * @param request
     * @return
     * @throws AdminException
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Vo paySubscribe(SubscribePayRequest request) throws AdminException {
        Subscribe subscribe = dao.get(Subscribe.class, request.getSubscribeId());
        if (subscribe == null) {
            throw new AdminException("预约单异常");
        }
        ServiceProject serviceProject = subscribe.getServiceProject();
        if (serviceProject == null) {
            throw new AdminException("服务项目异常");
        }
        subscribe.setSubscribeStatus(Subscribe.SubscribeStatus.paid);
        subscribe.setOriginalPrice(serviceProject.getProjectPrice());
        BigDecimal projectPrice = serviceProject.getProjectPrice();
        BigDecimal price = request.getPrice();
        if (request.getDiscount() != null) {
            price = price.multiply(request.getDiscount());
        }
        // Falg:  1：无卡扣费 2：会员卡积分结账 3：会员卡项目次数结账
        BigDecimal surplusPrice = BigDecimal.ZERO;
        BigDecimal surplusGivePrice = BigDecimal.ZERO;
        BigDecimal expendRatio = BigDecimal.ZERO;
        if (subscribe.getTechnicianUser().getExpendRatio() != null) {
            expendRatio = subscribe.getTechnicianUser().getExpendRatio();
        }
        if (request.getFlag() == 1) {
            subscribe.setPrice(request.getPrice());
            Subscribe save = subscribeRepository.save(subscribe);
            Account account = accountService.saveLessAccount(save, projectPrice, price, Account.AccountPayType.online, surplusPrice, surplusGivePrice);
//            userAccountStaffUserService.addUserAccountStaffUser(account,save,request.getStr());
            userAccountStaffUserService.paySubscribeUserAccountStaffUser(account, subscribe.getTechnicianUser(), expendRatio);
        }
        if (request.getFlag() == 2) {
            Subscribe save = subscribeRepository.save(subscribe);
            if (request.getCardId() == null) {
                throw new AdminException("选择会员卡");
            }
            UserCard userCard = dao.get(UserCard.class, request.getCardId());
            if (userCard == null) {
                throw new AdminException("此用户无卡");
            }
            if (UserCard.Status.off.toString().equals(userCard.getStatus().toString())) {
                throw new AdminException("此卡无效");
            }
            BigDecimal balance = userCard.getPrice().add(userCard.getGivePrice());
            if (balance.compareTo(price) == -1) {
                throw new AdminException("用户积分不足");
            }
            if (request.getSelected() == null) {
                throw new AdminException("选择扣费方式");
            }
            // selected  1 正常剩余扣费 2 赠送剩余扣费
            if (request.getSelected() == 2) {
                //赠送金额不足以支付
                if (userCard.getGivePrice().compareTo(price) == -1) {
                    price = price.subtract(userCard.getGivePrice());
                    userCard.setGivePrice(BigDecimal.ZERO);
                    userCard.setPrice(userCard.getPrice().subtract(price));
                    surplusPrice = userCard.getPrice().subtract(price);
                } else {
                    userCard.setGivePrice(userCard.getGivePrice().subtract(price));
                    surplusGivePrice = userCard.getGivePrice().subtract(price);
                }
            } else {
                if (userCard.getPrice().compareTo(price) == -1) {
                    price = price.subtract(userCard.getPrice());
                    userCard.setPrice(BigDecimal.ZERO);
                    userCard.setGivePrice(userCard.getGivePrice().subtract(price));
                    surplusGivePrice = userCard.getGivePrice().subtract(price);
                } else {
                    userCard.setPrice(userCard.getPrice().subtract(price));
                    surplusPrice = userCard.getPrice().subtract(price);
                }
            }
            Account account = accountService.saveLessAccount(save, projectPrice, price, Account.AccountPayType.vipCard, surplusPrice, surplusGivePrice);
//            userAccountStaffUserService.addUserAccountStaffUser(account,save,request.getStr());
            userAccountStaffUserService.paySubscribeUserAccountStaffUser(account, subscribe.getTechnicianUser(), expendRatio);
        }
        if (request.getFlag() == 3) {
            subscribe.setPrice(serviceProject.getProjectPrice());
            if (request.getCardId() == null) {
                throw new AdminException("选择会员卡");
            }
            UserCard userCard = dao.get(UserCard.class, request.getCardId());
            if (userCard == null) {
                throw new AdminException("此用户无卡");
            }
            UserCardServiceProjectCentre centre = userCardServiceProjectCentreRepository.findByDeletedFalseAndUserCardAndServiceProject(userCard, serviceProject);
            if (centre == null) {
                throw new AdminException("此用户无服务卡");
            }
            if (request.getSelected() == null) {
                throw new AdminException("选择扣费方式");
            }
            if (request.getSelected() == 2) {
                if (centre.getGiveCount() - 1L >= 0) {
                    centre.setGiveCount(centre.getGiveCount() - 1L);
                } else {
                    throw new AdminException("赠送次数不足");
                }
            } else {
                if (centre.getCount() - 1L >= 0) {
                    centre.setCount(centre.getCount() - 1L);
                } else {
                    throw new AdminException("剩余次数不足");
                }
            }

            centre.setRemarks(request.getRemarks());
            userCardServiceProjectCentreRepository.save(centre);
            Subscribe save = subscribeRepository.save(subscribe);
            Account account = accountService.saveLessAccount(save, projectPrice, price, Account.AccountPayType.vipCardProject, userCard.getPrice(), userCard.getGivePrice());
//            userAccountStaffUserService.addUserAccountStaffUser(account,save,request.getStr());
            userAccountStaffUserService.paySubscribeUserAccountStaffUser(account, subscribe.getTechnicianUser(), expendRatio);
        }
        return new Vo(HttpStatus.OK);
    }

    @Override
    public Vo changeSubscribeStatus(Long id, Subscribe.SubscribeStatus status, String str) throws AdminException {
        Subscribe subscribe = dao.get(Subscribe.class, id);
        if (subscribe == null) {
            throw new AdminException("此预约不存在");
        }
        if ("到店核销".equals(str)) {
            subscribe.setArrivalTime(System.currentTimeMillis());
        }
        if ("取消".equals(str)) {
            if (!subscribe.getSubscribeStatus().toString().equals(Subscribe.SubscribeStatus.confirmed.toString())) {
                throw new AdminException("此时已不能取消");
            }
        }
        subscribe.setSubscribeStatus(status);
        Subscribe save = subscribeRepository.save(subscribe);
        if ("取消".equals(str)) {
            try {
                subscribeMessage(save, save.getWxUser(), SubscribeMessage.UserType.client, "预约取消");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return new Vo(HttpStatus.OK);
    }

    @Override
    public BigDecimal countSubscribe(StaffSubscribeQuery countSubscribeQuery) throws AdminException {
        StringBuilder sql = new StringBuilder();
        sql.append("SELECT COALESCE(count(price),0) price FROM subscribe  where deleted = 0");
        if (countSubscribeQuery.getBeginTime() != null) {
            sql.append(" and create_time >=").append(countSubscribeQuery.getBeginTime());
        }
        if (countSubscribeQuery.getEndTime() != null) {
            sql.append(" and create_time <=").append(countSubscribeQuery.getEndTime());
        }
        if (countSubscribeQuery.getOrgId() != null) {
            sql.append(" and sys_dept_id =").append(countSubscribeQuery.getOrgId());
        }
        if (countSubscribeQuery.getStaffUserId() != null) {
            sql.append(" and technician_user_id =").append(countSubscribeQuery.getStaffUserId());
        }
        if (!"".equals(countSubscribeQuery.getSubscribeStatus().toString())) {
            sql.append(" and subscribe_status =").append(countSubscribeQuery.getSubscribeStatus().ordinal());
        }
        System.out.println(sql);
        Map<String, Object> query = new HashMap<>(16);
        List<Map> list = dao.findBySql2Map(sql.toString(), query);
        BigDecimal price = BigDecimal.ZERO;
        if (list.size() > 0) {
            if (list.get(0).get("price") != null || !"".equals(list.get(0).get("price"))) {
                price = new BigDecimal(String.valueOf(list.get(0).get("price")));
            }
        }
        return price;
    }

}
